home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / MacApp Release 10 / MacApp Release 10 - HD Ready / Libraries / Framework / Sources / UErrorMgr.cp < prev    next >
Encoding:
Text File  |  1996-04-03  |  13.2 KB  |  428 lines  |  [TEXT/MPS ]

  1. //----------------------------------------------------------------------------------------
  2. // UErrorMgr.cp 
  3. // Copyright © 1984-96 by Apple Computer, Inc. All rights reserved.
  4. //----------------------------------------------------------------------------------------
  5.  
  6. //----------------------------------------------------------------------------------------
  7. // Theory: courtesy of Larry Goldman
  8. //
  9. //  Using Error Message Tables
  10. //  
  11. // Part of MacApp's powerful failure handling facilities is the ability to give the user
  12. // useful alert messages. The MacApp Cookbook already explains how to use the common
  13. // features of the error reporting mechanism. But the messageLookup option is not
  14. // explained.Actually, this facility is not difficult to use, and allows the program to
  15. // report application-specific errors in the same way as other machine errors.
  16. //
  17. // Background
  18. //
  19. // To use the failure handling mechanism for custom errors, an exception handler must
  20. // first be posted using the CatchFailures routine.If an error is encountered, the Failure
  21. // routine must be called with application-defined parameter values. If, instead, the
  22. // routine completes without error, the exception handler is popped off the exception
  23. // handler stack with the Success routine.
  24. //
  25. // The Failure routine takes two parameters: error, which is an INTEGER, and message,
  26. // which is a LONGINT. During exception processing, these parameters are passed eventually
  27. // to the ErrorAlert global routine. ErrorAlert decodes the message parameter to determine
  28. // what alert to display and what subsititions need to be made.
  29. //
  30. // If the high word of the message is either messageLookup or messageAlternateRecovery, and if the
  31. // message table lookup is successful, then ErrorAlert will display MacApp's generic error
  32. // alert, which displays the alert message in the form: Could not ^2, because ^0. ^1.
  33. //
  34. // The first substitution (^2) is called the "operation", oropString, the ^0 substitution
  35. // is called the "reason", or errString, and the ^1 substitution is called the recovery.
  36. //
  37. // Message Tables
  38. //
  39. // If the high word of the message is messageLookup or messageAlternateRecovery, ErrorAlert uses message
  40. // tables, located in the application's resource file, to determine the text of each of
  41. // the substitutions that will be displayed in the "generic" error alert.
  42. //
  43. // In both message cases, the low word of the message parameter is used to lookup the
  44. // opString, and the error parameter is used to lookup the errString. In the messageLookup
  45. // case, the error parameter is also used to determine the recovery. In the messageAlternateRecovery
  46. // case, the low word of the message parameter is used, instead, to determine recovery.
  47. //
  48. // ErrorAlert uses the global procedure LookupErrString to search message tables for the
  49. // text to substitute into the alert. LookupErrString first scans the MacApp message
  50. // tables, and if the message cannot be found, then application message tables are
  51. // scanned.
  52. //
  53. // Each message table has two parts in the resource file: an 'errs' resource which
  54. // contains the list of index ranges, and a 'STR#' list of messages that correspond to
  55. // each index range. This allows a single text message to cover a range of indexes, if
  56. // necessary.
  57. //
  58. // The index ranges are specified as an array of three integers: the first is the lowest
  59. // index to which the message applies, the next is the highest index to which the message
  60. // applies, and the last integer is the item in the CString list that contains the text of
  61. // the message to use. The first line of the index table, the one that begins with the
  62. // whichList constant,is used to specify the resource number of the STR# list to use for
  63. // this index table.
  64. //
  65. // Here is a sample message index table:
  66. //
  67. //  resource 'errs' (1130, purgeable) { // application's operation table 
  68. //  {    whichList, 0, 2103; // indicates that STR# 2103 will be used by this table 
  69. //  -26001, -26001, 1;    // lowIndex, hiIndex, STR# item 
  70. //  -26002, -26002, 2;
  71. //  -26003, -26003, 3
  72. //  }
  73. //  };
  74. //
  75. // Here is the corresponding STR# list:
  76. //
  77. // resource 'STR#' (2103, purgeable) { // application's operation strings 
  78. //  {
  79. //  "use the saved configuration";
  80. //  "add another character";
  81. //  "accept the number"
  82. //  }
  83. //  };
  84. //
  85. // The application's resource file normally contains three sets of message tables: one
  86. // each for the operation, error and recovery strings. The resource numbers for the tables
  87. // are fixed: the application's operation table must have number 1130, the reason table
  88. // must have number 1128 and the recovery table must have number 1129.
  89. //
  90. //  Recipe
  91. //
  92. // To use application message tables:
  93. //
  94. // 1) Define constants for the application's message and error:
  95. //  CONST
  96. //  msgCantAcceptChar    = messageLookup + -26002;
  97. //  {Note: Applications should use errors between -26000 and -29999.}
  98. //  errCantAddChar= -26002;
  99. //  Adding the predefined constant messageLookup to the message signals ErrorAlert to use the message
  100. //  tables to find text to substitute into the generic alert.
  101. //
  102. //  2) Define the message tables in the application's resource file:
  103. //  First, the operation table and its STR# list:
  104. //  resource 'errs' (1130, purgeable) { // application's operation table 
  105. //  {    whichList, 0, 2103, // indicates that STR# 2103 will be used by this table 
  106. //  -26002, -26002, 1
  107. //  }
  108. //  };
  109. //  resource 'STR#' (2103, purgeable) { // application's operation strings 
  110. //  {
  111. //  "add another character"
  112. //  }
  113. //  };
  114. //
  115. // Next, the errortable and its STR# list:
  116. //  resource 'errs' (1128, purgeable) { // application's reason table 
  117. //  {    whichList, 0, 2101;
  118. //  -26002, -26002, 1
  119. //  }
  120. //  };
  121. //  resource 'STR#' (2101, purgeable) { // application's error reason strings 
  122. //  {
  123. //  "only ^3 characters are allowed"
  124. //  }
  125. //  };
  126. //
  127. // Note that ^3 can be used in any message CString. ErrorAlert always subsitutes the text
  128. // in the global variable gErrorParm3 for ^3, if present, in the message strings. Thus,
  129. // gErrorParm3 can be used by the application to further customize the alert according to
  130. // the context of the program at the time the error was encountered.
  131. //
  132. //  Finally, the recovery table and its STR# list:
  133. //  resource 'errs' (1129, purgeable) { // application's recovery table 
  134. //  {    whichList, 0, 2102;
  135. //  -26002, -26002, 1
  136. //  }
  137. //  };
  138. //  resource 'STR#' (2102, purgeable) { // application's error recovery strings 
  139. //  {
  140. //  "Delete some characters before adding new ones."
  141. //  }
  142. //  };
  143. //
  144. //  3) If, in the course of executing the program, an error is encountered, call Failure:
  145. //  PROCEDURE TMyEditText.AddCharacter(ch: CHAR);
  146. //  VAR
  147. //  fi    : FailInfo;
  148. //  PROCEDURE HandleFailure(error: INTEGER; message: LONGINT);
  149. //  BEGIN
  150. //  IF error = errCantAddChar THEN {if the error is recognized, fill in the param}
  151. //  NumToString(fMaxCharsAllowed, gErrorParm3);
  152. //  {Note: the error will be propagated automatically to exception handlers already
  153. //  posted on the exception handler stack.    Eventually, ErrorAlert will be called to
  154. //  display the message with the text located in the application's message tables.}
  155. //  END;
  156. //  BEGIN
  157. //  CatchFailures(fi, HandleFailure);{Setup an exception handler}
  158. //  IF NumOfChars = fMaxCharsAllowed THEN    {Assume fMaxCharsAllowed = 15, for
  159. //  example}
  160. //  Failure(errCantAddChar, msgCantAcceptChar){Can't add a char, so signal failure.}
  161. //  ELSE
  162. //  INHERITED AddCharacter(ch);{Can accept char}
  163. //  Success(fi);{Done with exception handler.}
  164. //  END;
  165. //
  166. // 4) If the character could not be added, then the generic alert will appear on the
  167. // screen with the text:
  168. // Could not add another character, because only 15 are allowed. Delete some characters
  169. // before adding new ones.
  170. //----------------------------------------------------------------------------------------
  171.  
  172.  
  173. #ifndef __UERRORMGR__
  174. #include "UErrorMgr.h"
  175. #endif
  176.  
  177. // MacApp
  178.  
  179. #ifndef __UAPPLEEVENTS__
  180. #include "UAppleEvents.h"
  181. #endif
  182.  
  183. //    #ifndef __UAPPLICATION__
  184. //    #include "UApplication.h"
  185. //    #endif
  186.  
  187. #ifndef __UDEBUG__
  188. #include "UDebug.h"
  189. #endif
  190.  
  191. //    #ifndef __UDISPATCHER__
  192. //    #include "UDispatcher.h"
  193. //    #endif
  194.  
  195. #ifndef __UFAILURE__
  196. #include "UFailure.h"
  197. #endif
  198.  
  199. #ifndef __UMACAPPGLOBALS__
  200. #include "UMacAppGlobals.h"
  201. #endif
  202.  
  203. #ifndef __UMACAPPUTILITIES__
  204. #include "UMacAppUtilities.h"
  205. #endif
  206.  
  207. #ifndef __UMEMORY__
  208. #include "UMemory.h"
  209. #endif
  210.  
  211. #ifndef __UMENUMGR__
  212. #include "UMenuMgr.h"
  213. #endif
  214.  
  215. #ifndef __USCRIPTING__
  216. #include "UScripting.h"
  217. #endif
  218.  
  219. // Toolbox
  220.  
  221. #ifndef __APPLEEVENTS__
  222. #include <AppleEvents.h>
  223. #endif
  224.  
  225. #ifndef __MEMORY__
  226. #include <Memory.h>
  227. #endif
  228.  
  229. #ifndef __PACKAGES__
  230. #include <Packages.h>
  231. #endif
  232.  
  233. #ifndef __RESOURCES__
  234. #include <Resources.h>
  235. #endif
  236.  
  237. #ifndef __TOOLUTILS__
  238. #include <ToolUtils.h>
  239. #endif
  240.  
  241. // ANSI
  242.  
  243. #ifndef __STDIO__
  244. #include <stdio.h>
  245. #endif
  246.  
  247.  
  248. //----------------------------------------------------------------------------------------
  249. //CStr255 gErrorParm3;
  250. ProcPtr gMacAppAlertFilter;
  251. Boolean gInFilter;
  252. Boolean gInhibitNestedHandling;            // Allow nested handling 
  253.  
  254. //========================================================================================
  255. // GLOBAL Procedures
  256. //========================================================================================
  257.  
  258. //----------------------------------------------------------------------------------------
  259. // ErrorAlert: 
  260. //----------------------------------------------------------------------------------------
  261. #pragma segment MAError
  262.  
  263. void ErrorAlert(OSErr err,
  264.                 long message)
  265. {
  266.     union Converter
  267.     {
  268.         struct
  269.         {
  270.             short hiWd, loWd;
  271.         } shortVal;
  272.         long message;
  273.     };
  274.  
  275.  
  276.     const long kMsgCmdErr = messageCommandError / 0x10000;
  277.     const long kMsgAlert = messageAlert / 0x10000;
  278.     const long kMsgLookup = messageLookup / 0x10000;
  279.     const long kMsgAltRecov = messageAlternateRecovery / 0x10000;
  280.  
  281.     CStr255 opString;
  282.     CStr255 errStr;
  283.     CStr255 recovery;
  284.     Converter c;
  285.     ResNumber alertID = phGenError;                    // the default alert
  286.     Boolean genericAlert = TRUE;
  287.     OSErr recovErr;
  288.  
  289.     c.message = message;
  290.  
  291.     switch (c.shortVal.hiWd)
  292.     {
  293.         case kMsgCmdErr:
  294.             CommandNumber theCommand = c.shortVal.loWd;
  295.             if (theCommand != cNoCommand)
  296.             {
  297.                 alertID = phCommandError;
  298.                 CommandToName(theCommand, opString);
  299.             }
  300.             break;
  301.  
  302.         case kMsgAlert:
  303.             alertID = c.shortVal.loWd;
  304.             genericAlert = FALSE;
  305.             break;
  306.  
  307.         case kMsgLookup:
  308.         case kMsgAltRecov:
  309.             LookupErrString(c.shortVal.loWd, errOperationsID, opString);
  310.             break;
  311.  
  312.         default:
  313.             GetIndString(opString, c.shortVal.hiWd, c.shortVal.loWd);
  314.             break;
  315.     }
  316.  
  317.     if (genericAlert)
  318.     {
  319.         LookupErrString(err, errReasonID, errStr);
  320.  
  321.         if (c.shortVal.hiWd == kMsgAltRecov)
  322.             recovErr = c.shortVal.loWd;
  323.         else
  324.             recovErr = err;
  325.  
  326.         LookupErrString(recovErr, errRecoveryID, recovery);
  327.  
  328.         ParamText((ConstStr255Param)&errStr, (ConstStr255Param)&recovery,
  329.             (ConstStr255Param)&opString, (ConstStr255Param)&gErrorParm3);
  330.  
  331.         if (opString.IsEmpty())
  332.             alertID = phUnknownErr;
  333.     }
  334.  
  335.     StdAlert(alertID);
  336.     gInhibitNestedHandling = FALSE;                // Used suppress nested event handling 
  337.  
  338.     if (genericAlert)
  339.         ResetAlertStage();
  340. } // ErrorAlert 
  341.  
  342. //----------------------------------------------------------------------------------------
  343. // StdAlert: 
  344. //----------------------------------------------------------------------------------------
  345. #pragma segment MAGlobalsRes
  346. // Don't require a segment load for this 
  347.  
  348. void StdAlert(ResNumber alertID)
  349. {
  350.     MacAppAlert(alertID, NULL);
  351. } // StdAlert 
  352.  
  353. //----------------------------------------------------------------------------------------
  354. // MacAppAlert: 
  355. //----------------------------------------------------------------------------------------
  356. // Don't require a segment load for this 
  357. #pragma segment MAGlobalsRes
  358.  
  359. short MacAppAlert(ResNumber alertID,
  360.                   ProcPtr filterProc)
  361. {
  362.     AlertTHndl alrtTemplate;
  363.     SignedByte savedState;
  364.     short alertReturn;
  365.  
  366.     gRsrcCheck = 0;                                // force immediate check. 
  367.  
  368.     // don't provide an idle proc, since we don't want events right now
  369.     MAInteractWithUserNoIdleProc();
  370.  
  371.     short oldResFile = MAUseResFile(gApplicationRefNum);
  372.  
  373.     SetCursor(&(qd.arrow));
  374.  
  375.     // preflight the ALRT 
  376.     alrtTemplate = (AlertTHndl)GetResource('ALRT', alertID);
  377.     if (!alrtTemplate)
  378.     {
  379. #if qDebug
  380.         CStr255 theString;
  381.         ConcatNumber("Unable to find or load 'ALRT' resource ", alertID, theString);
  382.         ProgramBreak(theString);
  383. #endif
  384.  
  385.         SysBeep(2);                                // At least give some indication 
  386.         MAUseResFile(oldResFile);
  387.         return cancel;                            // safe result 
  388.     }
  389.  
  390.     // preflight the DITL 
  391.     if (!GetResource('DITL', (*alrtTemplate)->itemsID))
  392.     {
  393. #if qDebug
  394.         CStr255 theString;
  395.         ConcatNumber("Unable to find or load 'DITL' resource ", alertID, theString);
  396.         ProgramBreak(theString);
  397. #endif
  398.  
  399.         SysBeep(2);                                // At least give some indication 
  400.         MAUseResFile(oldResFile);
  401.         return cancel;                            // safe result 
  402.     }
  403.  
  404.     // Success at last!
  405.     savedState = LockHandleHigh((Handle)alrtTemplate);
  406.  
  407.     // Assume that the bit is set in the ALRT template in order to do the centering.
  408.  
  409.     PullApplicationToFront();
  410.  
  411.     ProcPtr aProcPtr = (filterProc == NULL) ? gMacAppAlertFilter : filterProc;
  412.     ModalFilterUPP theFilter = NewModalFilterProc(aProcPtr);
  413.  
  414.     alertReturn = Alert(alertID, theFilter);
  415.  
  416.     theFilter = (ModalFilterUPP)DisposeIfRoutineDescriptor((UniversalProcPtr)theFilter);
  417.     
  418.     // restore the state of the DITL's handle
  419.     HSetState((Handle)alrtTemplate, savedState);
  420.     MAUseResFile(oldResFile);
  421.     return alertReturn;
  422. } // MacAppAlert 
  423.  
  424. //----------------------------------------------------------------------------------------
  425. // End of UErrorMgr.cp 
  426.  
  427. #pragma segment Inline
  428.